 /*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

 /**
 * Project  : EasyAvatar-Android
 * Package  : net.solosky.easyavatar.activity
 * File     : WebAuth.java
 * Author   : solosky < solosky772@qq.com >
 * Created  : 2011-11-11
 * License  : Apache License 2.0 
 */
package net.solosky.easyavatar.activity;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import net.solosky.easyavatar.R;
import net.solosky.easyavatar.api.ApiException;
import net.solosky.easyavatar.api.ErrorCode;
import net.solosky.easyavatar.api.OAuthFriendProvider;
import net.solosky.easyavatar.api.WebFriendProvider;
import net.solosky.easyavatar.bean.AuthInfo;
import net.solosky.easyavatar.bean.ProviderMeta;
import net.solosky.easyavatar.bean.ProviderMeta.AuthType;
import net.solosky.easyavatar.utils.AsyncTask;
import net.solosky.easyavatar.utils.Constants;
import net.solosky.easyavatar.utils.Globals;
import net.solosky.easyavatar.utils.Utils;
import net.solosky.easyavatar.utils.Views;

import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;

import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

/**
 *
 * 登录页面
 *
 * @author solosky <solosky772@qq.com>
 *
 */
public class Login extends Base implements OnClickListener, OnCancelListener, OnCheckedChangeListener {
	private ProviderMeta mProviderMeta;
	private WebFriendProvider mFriendProvider;
	private ProgressDialog mProgressDialog;
	private LoginingTask mLoginingTask;
	private RefreshingTask mRefreshingTask;
	private Drawable mCaptchaDrawable;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if(!checkInitilized()){ finish(); return; }
		
		setContentView(R.layout.ui_login);
		setupBackButton();
		
		boolean isInOAuth = false;
		String oauthCode = getSharedPreferences(Constants.DEFAULT_PREFS, 0).getString("oauth.provider.code", "null");
		String providerCode = null;
		if(getIntent().getStringExtra("provider.from")!=null){
			providerCode = getIntent().getStringExtra("provider.code");
		}else if(!oauthCode.equals("null")){
			isInOAuth = true;
			providerCode = oauthCode;
		}
		
		mProviderMeta = Utils.getProviderMeta(providerCode);
		if( mProviderMeta==null){
			Views.showToast(R.string.err_invalid_params);
			finish();
		}
		
		setTitle(mProviderMeta.getTitle());
		setupUI();
		
		//OAuth认证成功,传递回认证码
		if(isInOAuth){
			Uri uri = getIntent().getData();
			if(uri!=null && uri.getQueryParameter("oauth_token")!=null){
				new FinishOAuthTask().execute(null);
			}
		}else{
			//是否是自动登录？？
			AuthInfo authInfo = mProviderMeta.getAuthInfo();
			if(authInfo!=null && 
					mProviderMeta.getAuthType()==AuthType.WEB &&
					!Utils.isEmptyString(authInfo.getUsername()) &&
					!Utils.isEmptyString(authInfo.getPassword()) &&
					authInfo.isAutoLogin()){
				mLoginingTask = new LoginingTask();
				mLoginingTask.execute(null);
			}
		}
	}
	private void setupUI() {
		mProgressDialog = new ProgressDialog(this);
		mProgressDialog.setCancelable(true);
		mProgressDialog.setIndeterminate(true);
		mProgressDialog.setOnCancelListener(this);
		
		TextView tv = (TextView) findViewById(R.id.tv_provider_name);
		tv.setText(mProviderMeta.getTitle());
		tv = (TextView) findViewById(R.id.tv_provider_intro);
		tv.setText(mProviderMeta.getIntro());
		tv = (TextView) findViewById(R.id.tv_provider_tip);
		tv.setText(mProviderMeta.getAuthType()==AuthType.WEB?R.string.hint_webauth:R.string.hint_oauth);
		
		ImageView iv = (ImageView) findViewById(R.id.iv_provider_icon);
		iv.setImageResource(getResources().getIdentifier(mProviderMeta.getIconLarge(), "drawable", getPackageName()));
		
		Button bt = (Button) findViewById(R.id.bt_login);
		bt.setOnClickListener(this);
		bt.setText(mProviderMeta.getAuthType()==AuthType.OAUTH ? R.string.authronize : R.string.login);
		bt = (Button) findViewById(R.id.bt_refresh);
		bt.setOnClickListener(this);
		
		CheckBox cb = (CheckBox) findViewById(R.id.cb_auto_login);
		cb.setOnCheckedChangeListener(this);
		
		
		if(mProviderMeta.getAuthType()==AuthType.OAUTH){
			View v = findViewById(R.id.bl_webauth);
			v.setVisibility(View.GONE);
		}else if(mProviderMeta.getAuthInfo()!=null){
			AuthInfo authInfo = mProviderMeta.getAuthInfo();
			EditText et = (EditText) findViewById(R.id.et_login_account);
			et.setText(authInfo.getUsername());
			et = (EditText) findViewById(R.id.et_login_password);
			et.setText(authInfo.getPassword());
			cb = (CheckBox) findViewById(R.id.cb_auto_login);
			cb.setChecked(authInfo.isAutoLogin());
		}
	}

	@Override
	public void onCancel(DialogInterface arg0) {
		Utils.safeCancelTask(mLoginingTask);
		Utils.safeCancelTask(mRefreshingTask);
	}
	

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		AuthInfo authInfo = fillAuthInfo();
		authInfo.setAutoLogin(isChecked);
		if(!isChecked){
			authInfo.setPassword("");
		}
		Globals.DB_PERSIST.saveAuthInfo(authInfo);
	}
	
	@Override
	public void onClick(View v) {
		switch(v.getId()){
			case R.id.bt_login:
				if(mProviderMeta.getAuthType()==AuthType.WEB){
					AuthInfo  authInfo = fillAuthInfo();
					if(Utils.isEmptyString(authInfo.getUsername()) || Utils.isEmptyString(authInfo.getPassword())){
						Views.showMessage(Views.S(R.string.info), Views.S(R.string.err_userpass_is_empty), null);
						return;
					}
					
					String captchaCode = null;
					View viewCaptcha = findViewById(R.id.bl_captcha);
					if(viewCaptcha.getVisibility()==View.VISIBLE){
						EditText et = (EditText) findViewById(R.id.et_captcha);
						captchaCode = et.getText().toString();
						if(Utils.isEmptyString(captchaCode)){
							Views.showMessage(Views.S(R.string.info), Views.S(R.string.err_captcha_is_empty), null);
							return;
						}
					}
					
					//如果没有选中自动登录，不保存用户密码
					if(!authInfo.isAutoLogin()){
						authInfo.setPassword("");
					}
					Globals.DB_PERSIST.saveAuthInfo(authInfo);
					authInfo = fillAuthInfo();
					
					String[] params = {captchaCode};
					mLoginingTask = new LoginingTask();
					mLoginingTask.execute(params);
					
				}else{
					new ReadyOAuthTask().execute(null);
				}
			break;
				
		case R.id.bt_refresh:
			mRefreshingTask = new RefreshingTask();
			mRefreshingTask.execute(null);
			break;
			}
	}
	
	
	private AuthInfo fillAuthInfo(){
		AuthInfo authInfo = mProviderMeta.getAuthInfo();
		if(authInfo==null){
			authInfo = new AuthInfo();
			authInfo.setCode(mProviderMeta.getCode());
			mProviderMeta.setAuthInfo(authInfo);
		}
		EditText et = (EditText) findViewById(R.id.et_login_account);
		authInfo.setUsername(et.getText().toString());
		et = (EditText) findViewById(R.id.et_login_password);
		authInfo.setPassword(et.getText().toString());
		CheckBox cb = (CheckBox) findViewById(R.id.cb_auto_login);
		authInfo.setAutoLogin(cb.isChecked());
		return authInfo;
	}
	
	/**
	 * 登录异步任务
	 */
	private class LoginingTask extends AsyncTask<String, String, ErrorCode>{
		
		@Override
		protected void onPreExecute() {
			mProgressDialog.setMessage(getString(R.string.st_logining));
			mProgressDialog.show();
		}
		
		@Override
		protected void onPostExecute(ErrorCode result) {
			mProgressDialog.hide();
			if(result==ErrorCode.NO_ERROR){
				Globals.ACTIVE_FRIEND_PROVIDER = mFriendProvider;
				Intent intent = new Intent(Login.this, Friends.class);
				intent.putExtra("provider.code", mProviderMeta.getCode());
				startActivity(intent);
			}else if(result==ErrorCode.NEED_CAPTCHA || result==ErrorCode.WRONG_CAPTCHA){
				View v = findViewById(R.id.bl_captcha);
				v.setVisibility(View.VISIBLE);
				ImageView iv = (ImageView) findViewById(R.id.iv_cpatcha);
				iv.setImageDrawable(mCaptchaDrawable);
				Views.showToast(Views.E(result));
				EditText et = (EditText) findViewById(R.id.et_captcha);
				et.setText("");
			}else{
				View v = findViewById(R.id.bl_captcha);
				v.setVisibility(View.GONE);
				EditText et = (EditText) findViewById(R.id.et_captcha);
				et.setText("");
				
				Views.showMessage(getString(R.string.info), result.toString(), null);
			}
		}

		protected void onProgressUpdate(String... values) {
			mProgressDialog.setMessage(values[0]);
		}

		@Override
		protected ErrorCode doInBackground(String... params) {
			AuthInfo authInfo = mProviderMeta.getAuthInfo();
			
			//初始化接口对象
			if(mFriendProvider==null){
				try {
					Class providerClass = Class.forName(mProviderMeta.getClazz());
					mFriendProvider = (WebFriendProvider) providerClass.newInstance();
					mFriendProvider.init();
				} catch (ClassNotFoundException e) {
					return ErrorCode.INIT_ERROR;
				} catch (IllegalAccessException e) {
					return ErrorCode.INIT_ERROR;
				} catch (InstantiationException e) {
					return ErrorCode.INIT_ERROR;
				} catch (ApiException e) {
					return e.getErrorCode();
				} catch (IOException e) {
					return ErrorCode.IO_ERROR;
				}
			}
			
			try {
				String captcha = params!=null && params.length==1?params[0]:null;
				mFriendProvider.signIn(authInfo.getUsername(), authInfo.getPassword(), captcha);
				return ErrorCode.NO_ERROR;
			} catch (ApiException e) {
				if(e.getErrorCode()==ErrorCode.NEED_CAPTCHA || e.getErrorCode()==ErrorCode.WRONG_CAPTCHA){
					try {
						byte[] bytes = mFriendProvider.retireCpatcha();
						mCaptchaDrawable = new BitmapDrawable(new ByteArrayInputStream(bytes));
					} catch (ApiException ex) {
						return ex.getErrorCode();
					} catch (IOException ex) {
						return ErrorCode.IO_ERROR;
					}
				}
				return e.getErrorCode();
			} catch (IOException e) {
				return ErrorCode.IO_ERROR;
			}
		}
	}
	
	/**
	 *  
	 * 异步刷新验证码
	 *
	 * @author solosky <solosky772@qq.com>
	 *
	 */
	private class RefreshingTask extends AsyncTask<Void, String, ErrorCode>{
		@Override
		protected void onPostExecute(ErrorCode result) {
			mProgressDialog.hide();
			if(result==ErrorCode.NO_ERROR){
				ImageView iv = (ImageView) findViewById(R.id.iv_cpatcha);
				iv.setImageDrawable(mCaptchaDrawable);
				Views.showToast(R.string.ret_captcha_refreshed);
			}else{
				Views.showMessage(getString(R.string.info), Views.E(result), null);
			}
		}

		@Override
		protected void onPreExecute() {
			mProgressDialog.setMessage(getString(R.string.st_refreshing_captcha));
			mProgressDialog.show();
		}

		@Override
		protected ErrorCode doInBackground(Void... params) {
			try {
				byte[] bytes = mFriendProvider.retireCpatcha();
				mCaptchaDrawable = new BitmapDrawable(new ByteArrayInputStream(bytes));
				return ErrorCode.NO_ERROR;
			} catch (ApiException e) {
				return e.getErrorCode();
			} catch (IOException e) {
				return ErrorCode.IO_ERROR;
			}
		}
	}
	
	
	private class ReadyOAuthTask extends AsyncTask<Void, String, ErrorCode>{
		private String mAuthUrl;
		private Token  mRequestToken;

		@Override
		protected ErrorCode doInBackground(Void... params) {
			try {
				Class providerClass = Class.forName(mProviderMeta.getClazz());
				OAuthFriendProvider oauthFriendProvider = (OAuthFriendProvider) providerClass.newInstance();
				
				OAuthService oauthService = oauthFriendProvider.createOAuthService(mProviderMeta.getAppKey(), mProviderMeta.getAppSecret(), "oauth://Login");
				mRequestToken = oauthService.getRequestToken();
				mAuthUrl  = oauthService.getAuthorizationUrl(mRequestToken);
				Utils.dout(mRequestToken);
				
				Editor editor = getSharedPreferences(Constants.DEFAULT_PREFS, 0).edit();
				editor.putString("oauth.provider.code", mProviderMeta.getCode());
				editor.putString("oauth.request.token", mRequestToken.getToken());
				editor.putString("oauth.request.secret", mRequestToken.getSecret());
				editor.commit();	//保存在磁盘中，防止程序退出
				return ErrorCode.NO_ERROR;
			} catch (ClassNotFoundException e) {
				return ErrorCode.INIT_ERROR;
			} catch (IllegalAccessException e) {
				return ErrorCode.INIT_ERROR;
			} catch (InstantiationException e) {
				return ErrorCode.INIT_ERROR;
			}catch(Exception e){
				e.printStackTrace();
				return ErrorCode.IO_ERROR;
			}
		}

		@Override
		protected void onPreExecute() {
			mProgressDialog.setMessage(getString(R.string.st_loading_oauth_token));
			mProgressDialog.show();
		}

		@Override
		protected void onPostExecute(ErrorCode result) {
			mProgressDialog.hide(); 
			if(result==ErrorCode.NO_ERROR){	
				Views.showToast(R.string.hint_oauth_tip);
				Intent intent = new Intent();
				ComponentName name = new ComponentName("com.android.browser", "com.android.browser.BrowserActivity");
				intent.setComponent(name);
				intent.setData(Uri.parse(mAuthUrl));
				intent.setAction(Intent.ACTION_VIEW);
				startActivity(intent);
			}else{
				Views.showMessage(getString(R.string.info), result.toString(), null);
			}
		}
	}
	
	private class FinishOAuthTask extends AsyncTask<Void, String, ErrorCode>{
		@Override
		protected ErrorCode doInBackground(Void... params) {
			try {
				Class providerClass = Class.forName(mProviderMeta.getClazz());
				OAuthFriendProvider oauthFriendProvider = (OAuthFriendProvider) providerClass.newInstance();
				OAuthService oauthService = oauthFriendProvider.createOAuthService(mProviderMeta.getAppKey(), mProviderMeta.getAppSecret(), "oauth://Login");

				//auth://OAuth?oauth_token=a84a373d6459499fab97fe861401a498&oauth_verifier=105092
				SharedPreferences prefs =  getSharedPreferences(Constants.DEFAULT_PREFS, 0);
				Uri uri = getIntent().getData();
				Token requestToken = new Token(prefs.getString("oauth.request.token", null), prefs.getString("oauth.request.secret", null));
				Token authronizedToken = oauthService.getAccessToken(requestToken, new Verifier(uri.getQueryParameter("oauth_verifier")));
				
				AuthInfo auth = mProviderMeta.getAuthInfo();
				if(auth==null){
					auth = new AuthInfo();
					auth.setCode(mProviderMeta.getCode());
					mProviderMeta.setAuthInfo(auth);
				}
				
				auth.setToken(authronizedToken.getToken());
				auth.setSecret(authronizedToken.getSecret());
				auth.setExpired(mProviderMeta.getExpired()+System.currentTimeMillis()/1000);
				auth.setAuthorized(true);
				Globals.DB_PERSIST.saveAuthInfo(auth);
				
				Editor editor =prefs.edit();
				editor.putString("oauth.provider.code", "null");
				editor.putString("oauth.request.token", "null");
				editor.putString("oauth.request.secret", "null");
				editor.commit();
				return ErrorCode.NO_ERROR;
			} catch (ClassNotFoundException e) {
				return ErrorCode.INIT_ERROR;
			} catch (IllegalAccessException e) {
				return ErrorCode.INIT_ERROR;
			} catch (InstantiationException e) {
				return ErrorCode.INIT_ERROR;
			}catch(Exception e){
				e.printStackTrace();
				return ErrorCode.IO_ERROR;
			}
		}

		@Override
		protected void onPreExecute() {
			mProgressDialog.setMessage(getString(R.string.st_finishing_oath_access));
			mProgressDialog.show();
		}

		@Override
		protected void onPostExecute(ErrorCode result) {
			mProgressDialog.hide(); 
			if(result==ErrorCode.NO_ERROR){	
				Intent intent = new Intent(Login.this, Friends.class);
				intent.putExtra("provider.code", mProviderMeta.getCode());
				startActivity(intent);
			}else{
				Views.showMessage(getString(R.string.info), result.toString(), null);
			}
		}
		
		
		
	}
}
